﻿using LiteBlog.Common.Components;
using LiteBlog.Common.Entities;
using LiteBlog.Common.Enums;
using LiteBlog.Repositories.Common;
using LiteBlog.Repositories.Contracts;
using LiteBlog.Repositories.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace LiteBlog.Repositories
{
    public class StatRepository : DataAccess, IStatRepository
    {
        private BlogRepository _blogData;
        public BlogRepository BlogData
        {
            get { return _blogData; }
            set { _blogData = value; }
        }

        public StatRepository(IDataContext context, IXmlHelper xmlHelper)
            : base(context, xmlHelper)
        {
            _path = context.GetPath(DataStoreType.Stat, null);
        }

        public Stat Load()
        {
            var stat = new Stat();
            var root = _xmlHelper.Load(_path);
            stat.Path = _path;

            List<XElement> feedElems = new List<XElement>();
            List<XElement> delPostElems = new List<XElement>();

            stat.Visits = int.Parse(root.Element(Elem.Summary)
                                        .Element(Elem.Visits)
                                        .Attribute(Attr.Count)
                                        .Value);

            stat.Hits = int.Parse(root.Element(Elem.Summary)
                                      .Element(Elem.Hits)
                                      .Attribute(Attr.Count)
                                      .Value);

            stat.Feeds = new Dictionary<string, int>();
            foreach (var statElem in root.Element(Elem.Feeds)
                                         .Elements(Elem.Stat))
            {
                string id = statElem.Attribute(Attr.Id2).Value;
                int count = int.Parse(statElem.Attribute(Attr.Count)
                                              .Value);

                if (Stat.IsFeedKey(id))
                {
                    feedElems.Add(statElem);
                    stat.Feeds[id] = count;
                }
            }

            var monthElem = root.Element(Elem.MonthlyViews);
            var lastStatElem = monthElem.Elements(Elem.Stat)
                                        .LastOrDefault();
            var thisMonthId = Stat.GetMonthKey(DateTime.UtcNow); // Not in local time
            bool addNew = true;
            if (lastStatElem != null)
            {
                var lastId = lastStatElem.Attribute(Attr.Id2).Value;
                if (lastId == thisMonthId)
                {
                    stat.ViewsThisMonth = int.Parse(lastStatElem.Attribute(Attr.Count)
                                                                .Value);
                    addNew = false;
                }
            }

            if (addNew)
            {
                stat.ViewsThisMonth = 0;
                monthElem.Add(new XElement(Elem.Stat, 
                                new XAttribute(Attr.Id2, thisMonthId), 
                                new XAttribute(Attr.Count, 0)));
            }

            foreach (XElement feedElem in feedElems)
            {
                feedElem.Remove();
            }

            _xmlHelper.Save(root, _path);

            stat.PageVisits = _blogData.GetPublished().OrderByDescending(p => p.Views).ToDictionary(p => p.FileID);

            stat.MonthlyViews = root.Element(Elem.MonthlyViews)
                                    .Elements(Elem.Stat)
                                    .Select(elem => 
                                        new Tuple<string, int>(Stat.GetMonthFromKey(elem.Attribute(Attr.Id2).Value),
                                                              (int)elem.Attribute(Attr.Count)));

            return stat;
        }

        public void Save(Stat stat)
        {
            var root = _xmlHelper.Load(stat.Path);
            root.Element(Elem.Summary)
                .Element(Elem.Visits)
                .SetAttributeValue(Attr.Count,
                                   stat.Visits);
            root.Element(Elem.Summary)
                .Element(Elem.Hits)
                .SetAttributeValue(Attr.Count,
                                   stat.Hits);
            DateTime now = DateTimeHelper.Now;

            string todayKey = Stat.GetFeedKey(now);
            string yesKey = Stat.GetFeedKey(now.AddDays(-1));
            string twoKey = Stat.GetFeedKey(now.AddDays(-2));

            var feedsElem = root.Element(Elem.Feeds);
            foreach (KeyValuePair<string, int> kvp2 in stat.Feeds)
            {
                if (kvp2.Key == todayKey || kvp2.Key == yesKey || kvp2.Key == twoKey)
                {
                    XElement statElem = new XElement(Elem.Stat, 
                                            new XAttribute(Attr.Id2, kvp2.Key), 
                                            new XAttribute(Attr.Count, kvp2.Value));

                    feedsElem.Add(statElem);
                }
            }

            var monthElem = root.Element(Elem.MonthlyViews)
                                .Elements(Elem.Stat)
                                .Last();
            monthElem.SetAttributeValue(Attr.Count,
                                        stat.ViewsThisMonth);
            _xmlHelper.Save(root, stat.Path);
            _blogData.ChangeViews(stat.PageVisits);
        }
    }
}
